﻿#region zh-CHS 2006 - 2007 DemoSoft 团队 | en 2006 - 2007 DemoSoft Team

//     NOTES
// ---------------
//
// This file is a part of the G.O.S.E(Game Online Server Engine) for .NET.
//
//                 2006-2007 DemoSoft Team
//
//
// First Version : by H.Q.Cai - mailto:caihuanqing@hotmail.com

/***************************************************************************
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 ***************************************************************************/

#region zh-CHS 包含名字空间 | en Include namespace
using System;
using System.IO;
using System.Net;
using Demo_G.O.S.E.ServerEngine.Common;
using System.Diagnostics;
#endregion

namespace Demo_G.O.S.E.ServerEngine.Network
{
    /// <summary>
    /// 需发送的数据包的基类
    /// </summary>
    [MultiThreadedNoSupportgAttribute( "当前的类所有成员没有锁定(只在局部创建需发送的数据包),不支持多线程操作" )]
    public abstract class Packet
    {
        #region zh-CHS 类常量 | en Class Constants
        /// <summary>
        /// 
        /// </summary>
        private const long BUFFER_SIZE = 4096;
        #endregion

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 输出包的长度
        /// </summary>
        private long m_PacketLength;
        #endregion

        #region zh-CHS 构造和初始化和清理 | en Constructors and Initializers and Dispose
        /// <summary>
        /// 通过调用EnsureCapacity(...)来产生m_Stream
        /// </summary>
        /// <param name="iPacketID"></param>
        public Packet( long iPacketID )
        {
            m_PacketID  = iPacketID;
            m_PacketLength    = 0;
            m_Stream    = PacketWriter.Instance();  // 通过InternalCompile(...)的PacketWriter.ReleaseInstance(...)返回进入空闲的集合

            PacketProfile l_PacketProfile = PacketProfile.GetOutgoingProfile( iPacketID );
            if ( l_PacketProfile != null )
                l_PacketProfile.RegConstruct();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="iPacketID"></param>
        /// <param name="iLength"></param>
        public Packet( long iPacketID, long iPacketLength )
        {
            m_PacketID  = iPacketID;
            m_PacketLength    = iPacketLength;
            m_Stream    = PacketWriter.Instance( iPacketLength );  // 通过InternalCompile(...)的PacketWriter.ReleaseInstance(...)返回进入空闲的集合

            PacketProfile l_PacketProfile = PacketProfile.GetOutgoingProfile( iPacketID );
            if ( l_PacketProfile != null )
                l_PacketProfile.RegConstruct();
        }
        #endregion

        #region zh-CHS 属性 | en Properties
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 输出包的ID
        /// </summary>
        private long m_PacketID;
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public long PacketID
        {
            get { return m_PacketID; }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 输出包的输出流
        /// </summary>
        private PacketWriter m_Stream;
        #endregion
        /// <summary>
        /// 输出包的输出流
        /// </summary>
        public PacketWriter WriterStream
        {
            get { return m_Stream; }
        }
        #endregion

        #region zh-CHS 方法 | en Method
        /// <summary>
        /// 请求新的内存空间
        /// </summary>
        /// <param name="iLength"></param>
        public void Rebulid()
        {
            Release();

            m_Stream = PacketWriter.Instance();  // 通过Release(...)返回进入空闲的集合
        }

        /// <summary>
        /// 请求新的内存空间
        /// </summary>
        /// <param name="iLength"></param>
        public void Rebulid( int iLength )
        {
            Release();

            m_Stream = PacketWriter.Instance( iLength );  // 通过Release(...)返回进入空闲的集合
        }

        /// <summary>
        /// 表示数据已发送完成,释放请求过的加解压缩的内存
        /// </summary>
        public void Release()
        {
            if ( m_Stream != null )
            {
                m_Stream.Release(); // 返回进入空闲的集合
                m_Stream = null;
            }

            if ( m_CompiledBuffer != null )
            {
                m_Buffers.ReleaseBuffer( m_CompiledBuffer );
                m_CompiledBuffer = null;
            }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private long m_CompiledLength = 0;
        /// <summary>
        /// 
        /// </summary>
        private byte[] m_CompiledBuffer = null;
        /// <summary>
        /// 
        /// </summary>
        private static BufferPool m_Buffers = new BufferPool( "Packet - Compressed", 128, BUFFER_SIZE );
        #endregion
        /// <summary>
        /// 加密输出信息包的数据
        /// </summary>
        /// <param name="bCompress">是否需要Zip压缩</param>
        /// <param name="iOutLength">返回压缩或没有压缩后的数据长度</param>
        /// <returns>返回压缩或没有压缩数据</returns>
        public byte[] AcquireCompile( bool bCompress, out long iOutLength )
        {
            if ( m_Stream == null )
            {
                Debug.WriteLine( string.Format( "Packet.AcquireCompile(...) - m_Stream == null error! 信息包已被Release(...)释放过了-{0}!", GetType() ) );

                iOutLength = 0;
                return null;
            }

            if ( m_CompiledBuffer != null )
            {
                Debug.WriteLine( string.Format( "Packet.AcquireCompile(...) - m_CompiledBuffer != null warning! 信息包数据已被请求压缩处理过了-{0}!", GetType() ) );
                
                m_Buffers.ReleaseBuffer( m_CompiledBuffer );
                m_CompiledBuffer = null;
            }

            if ( m_PacketLength <= 0 )
                m_PacketLength = WriterStream.Length;
            else if ( WriterStream.Length != m_PacketLength )
            {
                long iDiff = WriterStream.Length - m_PacketLength;

                Debug.WriteLine( string.Format( "Packet.AcquireCompile(...) - WriterStream.Length != m_Length |0x{0:X2} ('{1}') (length={2} LengthDiff={3}{4})| error!", m_PacketID, GetType().Name, m_PacketLength, iDiff >= 0 ? "+" : "-", iDiff ) );

                iOutLength = 0;
                return null;
            }

            m_CompiledBuffer = m_Stream.Stream.GetBuffer();
            if ( m_CompiledBuffer == null )
            {
                Debug.WriteLine( string.Format( "Packet.AcquireCompile(...) - m_CompiledBuffer == null |0x{0:X2} ('{1}') (length={2})| error!", m_PacketID, GetType().Name, m_PacketLength ) );

                iOutLength = 0;
                return null;
            }

            long iStreamLength = m_Stream.Stream.Length;
            if ( bCompress )
            {
                // 暂时不支持Zip压缩
                //m_CompiledBuffer = Compression.Compress( m_CompiledBuffer, 0, iStreamLength, ref iStreamLength );

                if ( m_CompiledBuffer == null )
                {
                    Debug.WriteLine( string.Format( "Packet.AcquireCompile(...) - m_CompiledBuffer == null |0x{0:X2} ('{1}') (length={2})| error!", m_PacketID, GetType().Name, iStreamLength ) );
                    
                    iOutLength = 0;
                    return null;
                }
            }

            if ( iStreamLength > BUFFER_SIZE )
            {
                Debug.WriteLine( string.Format( "Packet.AcquireCompile(...) - iStreamLength > BUFFER_SIZE |0x{0:X2} ('{1}') (length={2})| error!", m_PacketID, GetType().Name, iStreamLength ) );
                
                iOutLength = 0;
                return null;
            }

            byte[] oldBuffer = m_CompiledBuffer;
            m_CompiledBuffer = m_Buffers.AcquireBuffer();
            Buffer.BlockCopy( oldBuffer, 0, m_CompiledBuffer, 0, (int)iStreamLength );

            iOutLength = m_CompiledLength = iStreamLength;
            return m_CompiledBuffer;
        }
        #endregion
    }
}
#endregion

